package core

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"syscall"
	"time"
	"tone-agent/entity"

	"github.com/google/uuid"
	"github.com/spf13/viper"
)

const RequestTimeout = 60

func GetHttpClient() *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	if viper.Get(entity.HttpProxy) != nil {
		uri, err := url.Parse(viper.GetString(entity.HttpProxy))
		if err != nil {
			MyLogger.WithFields(LogFields{"error": err.Error()}).Error("parse url error")
		} else {
			tr = &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
				// 设置代理
				Proxy: http.ProxyURL(uri),
			}
		}
	}

	client := &http.Client{
		Transport: tr,
		Timeout:   time.Duration(RequestTimeout) * time.Second,
	}
	return client
}

func GetCurTimeStr() string {
	timeUnix := time.Now().Unix()
	formatTimeStr := time.Unix(timeUnix, 0).Format("2006-01-02 15:04:05")
	return formatTimeStr
}

func GetSign() string {
	tsn := viper.GetString("tsn")
	t := time.Now()
	curTime := t.Unix()
	joinStr := fmt.Sprintf("%s|%d", tsn, curTime)
	sEnc := base64.StdEncoding.EncodeToString([]byte(joinStr))
	return sEnc
}

func FileExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}

func MakeDir(dir string) {
	defer os.MkdirAll(dir, os.ModePerm)
}

func WriteFile(file string, content []byte, perm os.FileMode) error {
	f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		MyLogger.WithFields(LogFields{"error": err.Error()}).Error("Open file failed!")
		return err
	}
	defer f.Close()
	if _, err := f.Write(content); err != nil {
		MyLogger.WithFields(LogFields{
			"error": err.Error(),
			"file":  file,
		}).Error("Write file failed!")
		return err
	}
	return nil
}

func CopyFile(sourceFile string, destinationFile string) {
	input, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		MyLogger.WithFields(LogFields{
			"error":           err.Error(),
			"sourceFile":      sourceFile,
			"destinationFile": destinationFile,
		}).Error("Copy file failed")
		return
	}
	if err2 := WriteFile(destinationFile, input, 0644); err2 != nil {
		MyLogger.WithFields(LogFields{
			"error":           err2.Error(),
			"sourceFile":      sourceFile,
			"destinationFile": destinationFile,
		}).Error("Copy file failed")
		return
	}
}

func ExecCommand(command string, args ...string) string {
	var stdout, stderr bytes.Buffer
	cmd := exec.Command(command, args...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	outStr, errStr := string(stdout.String()), string(stderr.String())
	if err != nil {
		MyLogger.WithFields(LogFields{
			"error":   err.Error(),
			"command": command,
			"result":  errStr,
		}).Error("Command execution failed")
		return fmt.Sprintf("Command execution failed!(%s)\n%s", err.Error(), outStr)
	}
	return outStr
}

// ExecByStdoutPipe 执行命令并实时输出其标准输出内容
func ExecByStdoutPipe(command string, args ...string) error {
	cmd := exec.Command(command, args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("failed to obtain stdout pipe: %v", err)
	}

	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to start command: %v", err)
	}

	done := make(chan error)
	go func() {
		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			line := scanner.Text()
			fmt.Println(line) // 实时打印新增内容
		}
		if err := scanner.Err(); err != nil {
			done <- fmt.Errorf("error reading stdout: %v", err)
			return
		}
		done <- nil
	}()

	// 等待命令执行完成
	if err := cmd.Wait(); err != nil {
		return fmt.Errorf("command finished with error: %v", err)
	}

	if err := <-done; err != nil {
		return err
	}

	return nil
}

func GenerateTsn() string {
	u := uuid.New()
	s := u.String()
	return strings.ToUpper(strings.Replace(s, "-", "", -1))

	//u := uuid.New()
	//s := u.String()
	//uid := strings.ToUpper(strings.Replace(s, "-", "", -1))
	//var array = [...]string{
	//	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
	//	"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
	//	"w", "x", "y", "z",
	//	"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
	//	"W", "X", "Y", "Z",
	//}
	//var buffer []string
	//for i := 0; i < 8; i++ {
	//	start := i * 4
	//	end := i*4 + 4
	//	b := []byte(uid[start:end])
	//	val := hex.EncodeToString(b)
	//	i, _ := strconv.Atoi(val)
	//	buffer = append(buffer, array[i%64])
	//}
	//return strings.Join(buffer, "")
}

// GetLocalIP 获取本机网卡IP
func GetLocalIP() string {
	var (
		addrs   []net.Addr
		addr    net.Addr
		ipNet   *net.IPNet // IP地址
		isIpNet bool
	)
	// 获取所有网卡
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	// 取第一个非lo的网卡IP
	for _, addr = range addrs {
		// 这个网络地址是IP地址: ipv4, ipv6
		if ipNet, isIpNet = addr.(*net.IPNet); isIpNet && !ipNet.IP.IsLoopback() {
			// 跳过IPV6
			if ipNet.IP.To4() != nil {
				return ipNet.IP.String() // 192.168.1.1
			}
		}
	}
	return ""
}

func CheckPid(pid int) bool {
	process, err := os.FindProcess(pid)
	if err != nil {
		MyLogger.WithFields(LogFields{"pid": pid}).Info("Unable to find the process")
		return false
	}

	err = process.Signal(syscall.Signal(0))
	if err != nil {
		MyLogger.WithFields(LogFields{"pid": pid}).Info("Process is dead")
		return false
	} else {
		MyLogger.WithFields(LogFields{"pid": pid}).Info("Process is alive")
		return true
	}
}

func GetValueFromMapWithDefault(data map[string]string, key, defaultValue string) string {
	if val, ok := data[key]; ok {
		return val
	}
	return defaultValue
}

func GetConfigFromViperWithDefault(configKey string, defaultValue string) string {
	configValue := viper.GetString(configKey)
	if configValue == "" {
		configValue = defaultValue
	}
	return configValue
}

// CheckRebootCommand 判断脚本字符串是否包含reboot命令
func CheckRebootCommand(script string) bool {
	re := regexp.MustCompile(`(?m)^\s*reboot\s*$`)
	matches := re.FindAllString(script, -1)
	return len(matches) > 0
}

func InputConfirm() bool {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Are you sure you want to proceed with this operation?[y/n]: ")
	input, _ := reader.ReadString('\n')
	return input == "y\n"
}

func UpdateConfig(tsn string, mode string, proxy string) error {
	if tsn == "" {
		tsn = viper.GetString(entity.TSNConfigKey)
	}
	if mode == "" {
		mode = viper.GetString(entity.ModeConfigKey)
	}
	if proxy == "" {
		proxy = viper.GetString(entity.ProxyConfigKey)
	}
	var configViper = viper.New()
	configViper.AddConfigPath(entity.ConfigPath)
	configViper.SetConfigName(entity.APPName)
	configViper.SetConfigType(entity.ConfigType)
	configViper.Set(entity.ModeConfigKey, mode)
	configViper.Set(entity.TSNConfigKey, tsn)
	configViper.Set(entity.ProxyConfigKey, proxy)
	return configViper.WriteConfig()
}

func Cron(fn func(), interval int) {
	for {
		fn()
		time.Sleep(time.Duration(interval) * time.Second)
	}
}
